import os

import openpyxl
import pandas as pd
from openpyxl import load_workbook
from concurrent.futures import ThreadPoolExecutor
from datetime import datetime
import warnings

from log_util import logger
from utils import format_date_column, clear_unnamed_header, remove_trailing_empty_rows, center_all_cells, \
    adjust_column_width

# 屏蔽 FutureWarning
warnings.simplefilter(action='ignore', category=FutureWarning)
# warnings.simplefilter(action='ignore', category=UserWarning)


def is_numeric(value):
    try:
        float(value)
        return True
    except ValueError:
        return False

# 辅助函数
def preprocess_data(df):
    # 统一空值格式（处理字符串型空值）
    df = df.replace(['nan', 'NaN', 'null', '', ' '], pd.NA)

    # 清理关键列（B列日期和G列数值）
    df.iloc[:, 1] = df.iloc[:, 1].astype(str).str.strip().replace('nan', pd.NA)
    df.iloc[:, 6] = pd.to_numeric(df.iloc[:, 6], errors='coerce')  # 确保G列为数值类型

    # 补全日期（精准定位需要补全的行）
    last_valid_date = None
    for index in range(len(df)):
        current_date = df.iat[index, 1]
        current_good = df.iat[index, 2]

        # 需要补全的条件：日期为空但货品存在
        if pd.isna(current_date) and not pd.isna(current_good):
            if last_valid_date is not None:
                df.iat[index, 1] = last_valid_date
        # 更新有效日期（仅当货品列也存在时）
        elif not pd.isna(current_date) and not pd.isna(df.iat[index, 2]):
            last_valid_date = current_date

    # 精确过滤汇总行（原始条件可能存在误伤）
    # 新条件：仅当F列为空且G列>0时才视为汇总行
    is_summary_row = (
            df.iloc[:, 5].isna() &
            df.iloc[:, 2].isna() &
            df.iloc[:, 6].notna() &
            (df.iloc[:, 6] > 0)
    )
    df = df[~is_summary_row]

    # 只要货品列（C列）存在就保留，即使日期为空（补全后应该不存在空日期）
    df = df[df.iloc[:, 2].notna()]  # C列非空

    # 删除全空行（排除货品列）
    df = df.dropna(
        how='all',
        subset=[col for col in df.columns if col != df.columns[2]]
    ).reset_index(drop=True)

    return df


def is_valid_date(date_str, date_range):
    """
    验证给定的日期时间字符串是否符合格式 YYYY-MM-DD HH:mm:ss 或 YYYY/MM/DD HH:mm:ss，
    并且日期部分是否在给定的日期范围内（要求日期范围的分隔符与输入日期一致）

    :param date_str: 待验证的日期时间字符串，格式为 'YYYY-MM-DD HH:mm:ss' 或 'YYYY/MM/DD HH:mm:ss'
    :param date_range: 元组，包含开始和结束日期（仅日期部分），格式必须与date_str的分隔符一致 YYYY-MM-DD
    :return: 如果日期时间格式有效且日期在范围内返回 True，否则返回 False
    """
    # 分割日期和时间部分
    try:
        date_part, time_part = date_str.split(' ', 1)
    except ValueError:
        return False  # 缺少时间部分

    # 确定日期分隔符
    separator = '-' if '-' in date_part else '/' if '/' in date_part else None
    if separator is None:
        return False

    # 生成格式模板
    datetime_format = f"%Y{separator}%m{separator}%d %H:%M:%S"
    date_only_format = f"%Y{separator}%m{separator}%d"

    try:
        # 解析完整日期时间
        date_val = datetime.strptime(date_str, datetime_format)
        # print(f"current date:{date_val}")
        # 解析日期范围（仅日期）
        start_date = datetime.strptime(date_range[0], date_only_format).date()
        end_date = datetime.strptime(date_range[1], date_only_format).date()
        # print(f"start_date:{start_date}, end_date:{end_date}")
    except Exception as e:
        # print(e)
        return False

    # 比较日期部分（忽略时间）
    return start_date <= date_val.date() <= end_date


def check_file(file_path, date_range):
    """检查文件有效性并返回处理后的DataFrame"""
    try:
        filename = os.path.basename(file_path)
        if filename.startswith('~$') or filename.startswith('.~'):
            print(f"跳过临时文件: {file_path}")
            return None

        # 读取Excel文件
        df = pd.read_excel(file_path, engine='openpyxl', header=None)

        # 检查行数限制
        if df.shape[0] > 1000:
            print(f"忽略行数过多的excel (行数超过了1000): {file_path}")
            logger.warning(f"忽略行数过多的excel (行数超过了1000): {file_path}")
            return None

        # 检查列数是否足够
        if df.shape[1] < 7:
            print(f'文件列数小于7列: {file_path}')
            return None

        # 预处理数据
        df = preprocess_data(df)

        # 验证日期和数值列有效性
        valid_date_mask = df.iloc[:, 1].apply(lambda x: is_valid_date(x, date_range))
        valid_number_mask = df.iloc[:, 6].apply(is_numeric)

        return df, valid_date_mask, valid_number_mask

    except Exception as e:
        print(f"文件检查失败 {file_path}: {e}")
        logger.error(f"文件检查失败 {file_path}: {e}")
        return None

def create_sum_file(original_path):
    """创建备份文件并返回路径，删除文件末尾的空行"""
    # 读取原始文件
    df = pd.read_excel(original_path)

    # 预处理数据
    df = preprocess_data(df)

    # 创建输出文件路径
    output_path = os.path.join(
        os.path.dirname(original_path),
        f"{os.path.splitext(os.path.basename(original_path))[0]}_sum.xlsx"
    )

    # 保存修改后的数据到新的文件
    df.to_excel(output_path, index=False)

    return output_path

def process_data(file_path, df, valid_date_mask, valid_number_mask, date_range, create_new_file=True):
    """处理数据并生成汇总结果
    Args:
        create_new_file: True-创建新文件，False-在原文件追加
    """
    try:
        # 应用有效性过滤
        valid_rows = df[valid_date_mask]
        total_sum = valid_rows.loc[valid_number_mask, df.columns[6]].astype(float).sum()

        if total_sum <= 0:
            return

        # 创建/选择输出文件
        if create_new_file:
            output_file = create_sum_file(file_path)  # 假设这是创建新文件的函数
            edit_mode = '新建文件'
        else:
            output_file = file_path
            edit_mode = '原文件追加'
            # 跳过临时文件保护
            if os.path.basename(output_file).startswith('~$'):
                print(f"跳过临时文件修改: {output_file}")
                return

        # 操作Excel文件
        wb = load_workbook(output_file)
        ws = wb.active

        # 生成合并单元格文本
        start_date_str, end_date_str = date_range
        summary_text = f"汇总时间段：{start_date_str} 至 {end_date_str}  总计：{total_sum:.2f}"

        # 确定写入行（兼容不同模式）
        last_row = ws.max_row + 1

        # 合并单元格并写入
        ws.merge_cells(start_row=last_row, start_column=1, end_row=last_row, end_column=7)
        summary_cell = ws.cell(row=last_row, column=1, value=summary_text)

        # 设置样式（新增原文件模式样式）
        from openpyxl.styles import Alignment, Font
        summary_cell.alignment = Alignment(horizontal='left', vertical='center')
        if not create_new_file:
            summary_cell.font = Font(bold=True, color="FF0000")  # 红色加粗突出显示

        # 保存文件（原文件模式需要强制覆盖）
        wb.save(output_file)
        print(f"[{edit_mode}] 汇总结果保存至：{output_file}")
        logger.info(f"[{edit_mode}] 汇总保存成功：{output_file}")

    except PermissionError as e:
        print(f"文件保存失败，请关闭已打开的Excel文件：{output_file}")
    except Exception as e:
        print(f"数据处理失败 {file_path}: {str(e)}")

def process_file(file_path, date_range,create_new_file):
    check_result = check_file(file_path, date_range)
    if check_result is None:
        return
    df, date_mask, num_mask = check_result
    process_data(file_path, df, date_mask, num_mask, date_range,create_new_file)


def clear_sum(directory):
    # 清理汇总文件
    for root, _, files in os.walk(directory):
        for file in files:
            if file.endswith('_sum.xlsx'):
                file_path = os.path.join(root, file)
                os.remove(file_path)  # 删除文件
                print(f"Deleted: {file_path}")


def process_excel_files(directory):
    for root, dirs, files in os.walk(directory):
        for file in files:
            # 仅处理非汇总的xlsx文件
            if file.endswith('.xlsx') and not file.endswith('_sum.xlsx'):
                original_path = os.path.join(root, file)
                sum_file = file.replace('.xlsx', '_sum.xlsx')
                sum_path = os.path.join(root, sum_file)

                # 检查汇总文件是否存在
                if os.path.exists(sum_path):
                    try:
                        # 读取汇总文件的最后一行数据
                        wb_sum = openpyxl.load_workbook(sum_path, read_only=True)
                        ws_sum = wb_sum.active
                        last_row = list(ws_sum.iter_rows(values_only=True))[-1]
                        wb_sum.close()

                        # 打开原始文件追加数据
                        wb_original = openpyxl.load_workbook(original_path)
                        ws_original = wb_original.active
                        ws_original.append(last_row)
                        wb_original.save(original_path)
                        wb_original.close()

                        print(f"成功更新：{original_path}")
                    except Exception as e:
                        print(f"处理文件时出错（{original_path}）: {str(e)}")
                else:
                    print(f"未找到汇总文件：{sum_path}")


def apply_to_files(process_func, directory, *args, **kwargs):
    """
    遍历目录并对符合过滤条件的文件执行处理函数

    Args:
        process_func (function): 处理单个文件的函数，接受文件路径作为参数
        directory (str): 要遍历的目录路径
        file_filter (function): 文件过滤函数，默认检查.xlsx后缀
    """
    file_filter = lambda f: f.endswith('.xlsx')

    for root, dirs, files in os.walk(directory):
        for file in files:
            if file_filter(file):
                file_path = os.path.join(root, file)
                print(f'Processing {file_path}')
                process_func(file_path, *args, **kwargs)

def main(directory, start_date, end_date, create_new_file):

    with ThreadPoolExecutor() as executor:
        futures = {executor.submit(process_file, os.path.join(root, file), (start_date, end_date), create_new_file): file
                   for root, _, files in os.walk(directory)
                   for file in files if file.endswith('.xlsx') and not file.startswith('~')}

        for future in futures:
            future.result()

if __name__ == "__main__":
    #### 汇总求和，生成sum求和文件
    dir_to_process = "work_dir/1"  # 替换为目标目录

    #### 方式一： 在原来文件末尾进行汇总
    # print("开始方式一汇总。。。")
    # start_date = '2025-02-01'  # 开始日期,格式严格使用 - 作为分隔符
    # end_date = '2025-02-28'  # 结束日期
    # 清理行末的空行
    # apply_to_files(remove_trailing_empty_rows, dir_to_process)
    # 在原来文件末尾进行汇总
    # main(dir_to_process, start_date, end_date,create_new_file=False)

    #### 方式二汇总,创建单独的sum汇总文件
    # print("开始方式二汇总。。。")
    # dir_to_process = "work_dir/账单 25.02.01-02.15_1"  # 替换为目标目录
    # print("清理汇总文件。。。")
    # clear_sum(dir_to_process)
    # 汇总
    # main(dir_to_process, start_date, end_date, create_new_file=True)
    # 合并汇总行到原来文件
    # process_excel_files(dir_to_process)
    # 清理生成的求和文件
    # print("清理汇总文件。。。")
    # clear_sum(dir_to_process)

    ######  调整日期格式,显示宽度，清除表头为 unamed的表头
    # apply_to_files(format_date_column, dir_to_process)
    # apply_to_files(clear_unnamed_header, dir_to_process)

    # 所有字段居中，overwrite=True 直接覆盖源文件
    # apply_to_files(center_all_cells, dir_to_process, overwrite=True)

    # 调整某列的宽度
    apply_to_files(adjust_column_width, dir_to_process, 'C', 20, overwrite=True)








